home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / Third Party SDKs / ATI RAVE SDK / Samples / Sprite / src / sprite.cpp
Encoding:
C/C++ Source or Header  |  1998-07-07  |  22.3 KB  |  994 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    Name:            sprite.cpp
  3.  *     
  4.  *  Author:            Chris Bentley 12/3/97, ATI Research Inc. Marlborough, MA
  5.  *
  6.  *  Description:    This is a simple demo showing the following:
  7.  *
  8.  *                    1)     using RAVE texture mapped triangles as sprites
  9.  *                    2)     using RAVE bitmaps as sprites
  10.  *                    3)    using alpha masking to create transparent sprites
  11.  *                    4)    using vertex alpha to blend or fade sprites 
  12.  *                    5)    shifting and rotate 2D sprites
  13.  *                    6)    using texture lighting from vertex colors to tint sprites
  14.  *
  15.  *                    Note: One restriction is that textures in RAVE must
  16.  *                    be power-of-two on each side (not necessarily square).  
  17.  *                    Non power-of-two bitmaps can be used by padding out
  18.  *                    to the next power-of-two and adjusting the u, v texture
  19.  *                    coordinates appropriately.  RAVE 'bitmaps' on the other
  20.  *                    hand can be any dimensions you want, but you can't rotate
  21.  *                    and scale them (that's what textures are for :-).
  22.  *
  23.  *                    I have run this on the Apple software RAVE renderer, and 
  24.  *                    on the ATI RageII and Rage Pro cards.  The 'scale' and 'pad'
  25.  *                    hacks were put in to keep the sprites from running off the edge
  26.  *                    of the window - with the RAVE software driver this causes very
  27.  *                    nasty crashes. The ATI hardware does the window clipping for you, 
  28.  *                    so these workarounds are disabled when running on it.  This code
  29.  *                    uses standard RAVE, so it _should_ run on other people's RAVE
  30.  *                    hardware.  Please feel free to use this code in any way you want.  
  31.  *
  32.  *                    Here is some timing info for this code, running on a PowerPC 9600,
  33.  *                    64MB RAM, 225 Mhz, 6409x480x16:
  34.  *
  35.  *                        On Apple RAVE software        -  32 fps
  36.  *                        On ATI RageII hardware        -  55 fps
  37.  *                        On ATI Rage Pro hardware    - 165 fps
  38.  *
  39.  *                    For more info on the RAVE API check out:
  40.  *
  41.  *                        gemma.apple.com/dev/games/
  42.  *
  43.  *                    For more info on the latest ATI RAVE hardware and drivers
  44.  *                    check out:
  45.  *
  46.  *                        www.atitech.ca
  47.  *
  48.  *                    or send email to:
  49.  *
  50.  *                        devrel@atitech.ca (and tell them Chris Bentley sent you :-)
  51.  *
  52.  */
  53. /****************************************************************/
  54. /* headers                                                        */
  55. /****************************************************************/
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include <math.h>
  60. #include <Timer.h>
  61. #include "RAVE.h"
  62.  
  63. /****************************************************************/
  64. /* defines                                                        */
  65. /****************************************************************/
  66. #define LEFT    20
  67. #define TOP        40
  68. #define WIDTH    600
  69. #define HEIGHT    400
  70.  
  71. #define BRICK_RES_ID    128
  72. #define SUN_RES_ID        129
  73.  
  74. #define MBAR_RES_ID            128
  75.  
  76. #define APPLE_MENU_ID        128
  77. #define FILE_MENU_ID        129
  78. #define ENGINE_MENU_ID        130
  79.  
  80. #define QUIT_ITEM            1
  81.  
  82. #define MAX_ENGINE            5
  83.  
  84. /*
  85.  * macro to load fields of TQAVGouraud
  86.  */
  87. #define SG( v, _x, _y, _z, _invW, _a, _r, _g, _b )            \
  88. {                                                            \
  89.     (v).x = (_x);                                            \
  90.     (v).y = (_y);                                            \
  91.     (v).z = (_z);                                            \
  92.     (v).invW = (_invW);                                        \
  93.     (v).a = (_a);                                            \
  94.     (v).r = (_r);                                            \
  95.     (v).g = (_g);                                            \
  96.     (v).b = (_b);                                            \
  97. }
  98.  
  99. /*
  100.  * macro to load fields of TQAVTexture
  101.  */
  102. #define ST( _v,_x,_y,_z,_invW,_a,_r,_g,_b,_uOverW,_vOverW,_kd_r,_kd_g,_kd_b,_ks_r,_ks_g,_ks_b ) \
  103. {                                                             \
  104.     (_v).x         = (_x);                                        \
  105.     (_v).y         = (_y);                                        \
  106.     (_v).z         = (_z);                                        \
  107.     (_v).invW     = (_invW);                                    \
  108.     (_v).a         = (_a);                                        \
  109.     (_v).r         = (_r);                                        \
  110.     (_v).g         = (_g);                                        \
  111.     (_v).b         = (_b);                                        \
  112.     (_v).uOverW = (_uOverW);                                \
  113.     (_v).vOverW = (_vOverW);                                \
  114.     (_v).kd_r     = (_kd_r);                                    \
  115.     (_v).kd_g     = (_kd_g);                                    \
  116.     (_v).kd_b     = (_kd_b);                                    \
  117.     (_v).ks_r     = (_ks_r);                                    \
  118.     (_v).ks_g     = (_ks_g);                                    \
  119.     (_v).ks_b     = (_ks_b);                                    \
  120. }
  121.  
  122. /*
  123.  * macros to update positions of sprites
  124.  */
  125. #define Translate( _x, _y, _xinc, _yinc, _image )            \
  126. {                                                            \
  127.     if( _x >= WIDTH-pad )     _xinc = -1;                        \
  128.     if( _x < pad )          _xinc =  1;                        \
  129.     if( _y >= HEIGHT-pad )     _yinc = -1;                        \
  130.     if( _y < pad )          _yinc =  1;                        \
  131.                                                             \
  132.     _x         += _xinc;                                        \
  133.     _y         += _yinc;                                        \
  134.                                                             \
  135.     V[0].x = _x;                                            \
  136.     V[0].y = _y - _image.height * scale;                    \
  137.     V[1].x = _x;                                            \
  138.     V[1].y = _y;                                            \
  139.     V[2].x = _x + _image.width * scale;                        \
  140.     V[2].y = _y;                                            \
  141.     V[3].x = _x + _image.width * scale;                        \
  142.     V[3].y = _y - _image.height * scale;                    \
  143. }
  144.  
  145. #define Rotate( _x, _y, _angle, _image)                        \
  146. {                                                            \
  147.     _angle     = (_angle == 360) ? 0 : _angle + 5;                \
  148.                                                             \
  149.     xoff = _image.width * scale * Cos[_angle];                \
  150.     yoff = _image.height * scale * Sin[_angle];                \
  151.                                                             \
  152.     V[0].x = _x - yoff;                                        \
  153.     V[0].y = _y - xoff;                                        \
  154.     V[1].x = _x;                                            \
  155.     V[1].y = _y;                                            \
  156.     V[2].x = _x + xoff;                                        \
  157.     V[2].y = _y - yoff;                                        \
  158.     V[3].x = V[2].x - yoff;                                    \
  159.     V[3].y = V[2].y - xoff;                                    \
  160. }
  161.  
  162. /*
  163.  * utility macros
  164.  */
  165. #define USHRT_MAX                    65535U
  166. #define ONE_SECOND                    1000000
  167. #define MILLIONTHS                    0.000001F
  168. #define MAX( a, b )                    ( ((a) > (b)) ? (a) : (b) )
  169. #define DEG2RAD( a )                  ( (double)((a) * 0.0174532925199432) )
  170. #define RAD2DEG( a )                  ( (double)((a) * 57.295779513082320) )
  171. #define rand()                        ((32767+Random()) * 1.0/65536.0)
  172.  
  173. /****************************************************************/
  174. /* typedefs                                                        */
  175. /****************************************************************/
  176. typedef unsigned char UINT8;
  177. typedef unsigned short UINT16;
  178. typedef long INT32;
  179. typedef unsigned long UINT32;
  180.  
  181. /****************************************************************/
  182. /* prototypes                                                    */
  183. /****************************************************************/
  184. /*
  185.  * initialization functions
  186.  */
  187. void InitTables( void );
  188. void InitMac( void );
  189. int InitWindow( void );
  190. int InitRAVE( void );
  191. TQAEngine *FindEngine( TQADevice *device );
  192. GDHandle FindWindowDevice( WindowPtr pWin );
  193. void FindWindowContentRect( WindowPtr pWin, Rect *r );
  194. int SetupRAVE( void );
  195. int SetupRAVETex( void );
  196. void MenuBarInit( void );
  197.  
  198. /*
  199.  * Event handling functions
  200.  */
  201. void EventLoop( void );
  202. void HandleMouseDown( EventRecord *pevent );
  203. void HandleMenuChoice( INT32 i32menuChoice );
  204. void HandleAppleChoice( UINT32 u32TheItem );
  205. void HandleFileChoice( UINT32 u32TheItem );
  206. void HandleEngineChoice( UINT32 u32TheItem );
  207.  
  208. /*
  209.  * utility functions
  210.  */
  211. void redraw( void );
  212. void Cleanup( void );
  213. void DisplayString( int x, int y, char *str );
  214. UINT32 MicrosecondCount( void );
  215. int LoadImageFromResource(     short resID, UINT8 depth, UINT8 alpha, 
  216.                             TQAImage *map, TQAImagePixelType *pixelType );
  217.  
  218. /****************************************************************/
  219. /* global variables                                                */
  220. /****************************************************************/
  221. /*
  222.  * RAVE variables
  223.  */
  224. GDHandle        gGDevice;
  225. TQADevice       gDevice;
  226. TQAEngine       *gEngine;
  227. TQADrawContext  *gDrawContext;
  228. TQATexture         *gpTex;
  229. TQABitmap         *gpBit;
  230. TQAVTexture        V[4];
  231. TQAVGouraud     VG;
  232. TQAImage         gImageTex;
  233. TQAImage         gImageBit;
  234. TQAImagePixelType pixelType;
  235. unsigned long    gflags = kQAContext_DoubleBuffer | kQAContext_NoZBuffer;
  236. TQARect         gRect     = { LEFT, LEFT+WIDTH, TOP, TOP+HEIGHT };
  237. TQAEngine         *EngineList[MAX_ENGINE] = { NULL, NULL, NULL, NULL, NULL };
  238. char            EngineNames[MAX_ENGINE][100];
  239. unsigned long    gEngineID = 0;
  240.  
  241. /*
  242.  * window variables
  243.  */
  244. MenuHandle        gAppleMenu;
  245. MenuHandle        gFileMenu;
  246. MenuHandle        gEngineMenu;
  247. Boolean         gbDone = false;
  248. Boolean            gbTexAlpha = true;
  249. Boolean            gbATIcard = false;
  250. int                gNumEngines = 0;
  251. WindowPtr        winPtr = NULL;
  252. Rect            winRect = { TOP, LEFT, TOP+HEIGHT, LEFT+WIDTH };
  253. RGBColor        BLACK = { 0, 0, 0 };
  254. GWorldPtr        newGW;
  255.  
  256. /*
  257.  * sprite + misc variables
  258.  */
  259. int                x1 = 140, y1 = 150;
  260. int                x2 = 230, y2 = 270;
  261. int                x3 = 240, y3 = 175;
  262. int                x4 = 190, y4 = 300;
  263. int                xinc1 = 1, yinc1 = 1;
  264. int                xinc2 = -1, yinc2 = -1;
  265. int                xinc3 = -1, yinc3 = 1;
  266. int                xinc4 = 1, yinc4 = -1;
  267. UINT32            start, end;
  268. float            seconds;
  269. UINT32            count = 0;
  270. float            sum = 0.0;
  271. char             str[100];
  272. int                angle = 0;
  273. float            xoff, yoff;
  274. double            Cos[361], Sin[361];
  275. float            pad = 0;
  276. float            scale = 1;
  277.  
  278. /****************************************************************/
  279. /* code                                                            */
  280. /****************************************************************/
  281. /*
  282.  * Function:    main()
  283.  *
  284.  */
  285. void main( void )
  286. {
  287.     /*
  288.      * initialize sin, cos tables
  289.      */
  290.     InitTables();
  291.     
  292.     /*
  293.      * initialize Toolbox + window
  294.      */
  295.     InitMac();
  296.     
  297.     if( !InitWindow() || !SetupRAVE() )
  298.     {
  299.         Cleanup();
  300.         return;
  301.     }
  302.     
  303.     redraw();
  304.     
  305.     EventLoop();
  306.     
  307.     /*
  308.      * end
  309.      */
  310.     Cleanup();
  311. }
  312.  
  313. /*
  314.  * Function:    InitTables()
  315.  *
  316.  */
  317. void InitTables( void )
  318. {
  319.     for( int angle = 0; angle <= 360; angle++ )
  320.     {
  321.         Cos[angle] = cos( DEG2RAD(angle) );
  322.         Sin[angle] = sin( DEG2RAD(angle) );
  323.     }
  324. }
  325.  
  326. /*
  327.  * Function:    InitMac()
  328.  *
  329.  */
  330. void InitMac( void )
  331. {
  332.     OSErr        error;
  333.     SysEnvRec    theWorld;
  334.         
  335.     /*
  336.      *    Test the computer to be sure we can do color.  
  337.      *    If not we would crash, which would be bad.  
  338.      *    If we can’t run, just beep and exit.
  339.      */
  340.     error = SysEnvirons( 1, &theWorld );
  341.     if( theWorld.hasColorQD == false ) 
  342.         ExitToShell();
  343.     
  344.     /* 
  345.      * Initialize all the needed managers. 
  346.      */
  347.     InitGraf( &qd.thePort );
  348.     InitFonts();
  349.     InitWindows();
  350.     InitMenus();
  351.     TEInit();
  352.     InitDialogs( NULL );
  353.     InitCursor();
  354.         
  355.     GetDateTime((unsigned long*) &qd.randSeed);
  356.     
  357.     MenuBarInit();
  358. }
  359.  
  360. /*
  361.  * Function:    InitWindow()
  362.  *
  363.  */
  364. int InitWindow( void )
  365. {
  366.     if( (winPtr = NewCWindow( NULL, &winRect, "\pRAVE Sprite Demo", true, 
  367.                                  noGrowDocProc, (WindowPtr)-1, false, 0 )) == NULL )
  368.     {
  369.         printf( "ERROR: opening window\n" );
  370.         return( false );
  371.     }
  372.     
  373.     return( true );
  374. }
  375.  
  376. /*
  377.  * Function:    InitRAVE()
  378.  *
  379.  */
  380. int InitRAVE( void )
  381. {
  382.     Rect    r;
  383.     
  384.     if( (gGDevice =  FindWindowDevice(winPtr)) == NULL )
  385.     {
  386.          printf( "ERROR: No monitors found\n" );
  387.          return( false );
  388.     }
  389.  
  390.     gDevice.deviceType         = kQADeviceGDevice;
  391.     gDevice.device.gDevice     = gGDevice;
  392.     
  393.     if( (gEngine = FindEngine( &gDevice )) == NULL )
  394.     {
  395.          printf( "ERROR: No Engine available\n" );
  396.          return( false );
  397.     }
  398.  
  399.     if( QAEngineCheckDevice( gEngine, &gDevice ) )
  400.     {
  401.          printf( "ERROR: EngineCheckDevice failed\n" );
  402.          return( false );
  403.     }
  404.  
  405.     FindWindowContentRect( winPtr, &r );
  406.     OffsetRect( &r, -(**gGDevice).gdRect.left, -(**gGDevice).gdRect.top );
  407.     
  408.     gRect.left         = r.left; 
  409.     gRect.top          = r.top;  
  410.     gRect.right      = r.right;
  411.     gRect.bottom     = r.bottom;
  412.         
  413.     return( true );
  414. }
  415.  
  416. void FindWindowContentRect( WindowPtr pWin, Rect *r )
  417. {
  418.     GrafPtr    oldPort;
  419.     Point    leftTop;
  420.     Point    rightBot;
  421.     
  422.     GetPort( &oldPort );
  423.     
  424.     SetPort( pWin );
  425.     SetPt( &leftTop, pWin->portRect.left, pWin->portRect.top );
  426.     SetPt( &rightBot, pWin->portRect.right, pWin->portRect.bottom );
  427.     
  428.     LocalToGlobal( &leftTop );
  429.     LocalToGlobal( &rightBot );
  430.     
  431.     SetRect( r, leftTop.h, leftTop.v, rightBot.h, rightBot.v );
  432.     
  433.     SetPort( oldPort );
  434. }
  435.  
  436. /*
  437.  * Function:    FindWindowDevice()
  438.  *
  439.  */
  440. GDHandle FindWindowDevice( WindowPtr pWin )
  441. {
  442.     GDHandle    hDevice;
  443.     Rect        rWin;
  444.     Rect        intersect;
  445.     
  446.     if( pWin == NULL )
  447.         return( NULL );
  448.         
  449.     rWin = ((*(((WindowPeek)pWin)->strucRgn))->rgnBBox);
  450.     
  451.     for( hDevice = GetDeviceList(); 
  452.          hDevice; 
  453.          hDevice = GetNextDevice(hDevice) )
  454.     {
  455.         /*
  456.          * test for active monitors that entirely contain rect
  457.          */
  458.         if( TestDeviceAttribute(hDevice, screenDevice) &&
  459.             TestDeviceAttribute(hDevice, screenActive) &&
  460.             SectRect(&rWin, &((*hDevice)->gdRect), &intersect) &&
  461.             EqualRect(&rWin, &intersect) )
  462.         {
  463.             return( hDevice );
  464.         }    
  465.     }
  466.  
  467.     return( NULL );    
  468. }
  469.  
  470. TQAEngine *FindEngine( TQADevice *device )
  471. {
  472.     TQAEngine     *tmpEngine;
  473.     UINT32        vendorID;
  474.     char        Response[200];
  475.     int            i, len;
  476.     int            saveEngineID;
  477.     Str255        menuStr;
  478.     MenuHandle    menuHndl    = gEngineMenu;
  479.     
  480.     saveEngineID     = gEngineID;
  481.     gEngineID        = 0;
  482.     
  483.     for( i = 0; i < gNumEngines; i++ )
  484.     {
  485.         CheckItem( gEngineMenu, i+1, false );
  486.         DisableItem( gEngineMenu, i+1 );
  487.     }
  488.     
  489.     /*
  490.      * list all RAVE engines
  491.      */
  492.     for( tmpEngine = QADeviceGetFirstEngine(device);
  493.          tmpEngine;
  494.          tmpEngine = QADeviceGetNextEngine(device, tmpEngine) )
  495.     {
  496.         QAEngineGestalt( tmpEngine, kQAGestalt_ASCIIName, Response );
  497.         
  498.         /*
  499.          * see if engine is already in list
  500.          */
  501.         for( i = 0; i < gNumEngines; i++ )
  502.         {
  503.             if( strcmp(Response, EngineNames[i]) == 0 )
  504.             {
  505.                 EngineList[i] = tmpEngine;
  506.                 EnableItem( gEngineMenu, i+1 );
  507.                 
  508.                 if( i == saveEngineID )
  509.                     gEngineID = i;
  510.                 break;
  511.             }
  512.         }
  513.  
  514.         /*
  515.          * if engine is not already in list add it
  516.          */        
  517.         if( i == gNumEngines )
  518.         {
  519.             EngineList[gNumEngines] = tmpEngine;
  520.             strcpy( EngineNames[gNumEngines], Response );
  521.         
  522.             menuStr[0] = strlen( Response );
  523.             strcpy( (char *)(menuStr+1), Response );
  524.         
  525.             AppendMenu( gEngineMenu, menuStr );
  526.             
  527.             if( ++gNumEngines == MAX_ENGINE )
  528.                 break;
  529.         }
  530.     }    
  531.     
  532.     if( gEngineID >= gNumEngines )
  533.         gEngineID = 0;
  534.     
  535.     CheckItem( gEngineMenu, gEngineID+1, true );
  536.  
  537.     QAEngineGestalt( EngineList[gEngineID], kQAGestalt_VendorID, &vendorID );        
  538.     gbATIcard     = (vendorID == 1);
  539.  
  540.     return( EngineList[gEngineID] );
  541. }
  542.  
  543. int SetupRAVE( void )
  544. {    
  545.     if( !InitRAVE() )
  546.         return( false );
  547.         
  548.     /*
  549.      * create a draw context + set background color for clearing
  550.      */
  551.     if( QADrawContextNew(&gDevice,&gRect,0,gEngine,gflags,&gDrawContext) != kQANoErr )
  552.     {
  553.          printf( "ERROR: Context create failed\n" );
  554.          Cleanup();
  555.          return( false );
  556.     }
  557.     
  558.     QASetFloat( gDrawContext, kQATag_ColorBG_a, 1.0 );
  559.     QASetFloat( gDrawContext, kQATag_ColorBG_r, 1.0 );
  560.     QASetFloat( gDrawContext, kQATag_ColorBG_g, 0.0 );
  561.     QASetFloat( gDrawContext, kQATag_ColorBG_b, 0.0 );
  562.  
  563.     /*
  564.      * load image for texture
  565.      */    
  566.     if( !LoadImageFromResource(SUN_RES_ID, 16, true, &gImageTex, &pixelType) )
  567.     {
  568.          printf( "ERROR: loading bitmap resource failed\n" );
  569.          Cleanup();
  570.          return( false );
  571.     }    
  572.     
  573.     /*
  574.      * register texture with RAVE
  575.      */
  576.     QATextureNew( gEngine, kQATexture_None, pixelType, &gImageTex, &gpTex );
  577.         
  578.     if( gpTex == NULL )
  579.     {
  580.          printf( "ERROR: RAVE bitmap registration failed\n" );
  581.          Cleanup();
  582.          return( false );
  583.     }    
  584.     
  585.     QATextureDetach( gEngine, gpTex );
  586.     DisposeGWorld( newGW );
  587.     
  588.     /*
  589.      * load image
  590.      */    
  591.     if( !LoadImageFromResource(BRICK_RES_ID, 16, false, &gImageBit, &pixelType) )
  592.     {
  593.          printf( "ERROR: loading bitmap resource failed\n" );
  594.          Cleanup();
  595.          return( false );
  596.     }    
  597.     
  598.     /*
  599.      * register bitmap with RAVE
  600.      */
  601.     QABitmapNew( gEngine, kQABitmap_None, pixelType, &gImageBit, &gpBit );
  602.         
  603.     if( gpBit == NULL )
  604.     {
  605.          printf( "ERROR: RAVE bitmap registration failed\n" );
  606.          Cleanup();
  607.          return( false );
  608.     }    
  609.     
  610.     QABitmapDetach( gEngine, gpBit );
  611.     DisposeGWorld( newGW );
  612.     
  613.     /*
  614.      *    initialize Gouraud vertex for anchoring top left corner of bitmap sprite
  615.      */
  616.     //      x  y  z 1/W a  r  g  b
  617.     SG( VG, 0, 0, 1, 1, 1, 1, 1, 1 );
  618.  
  619.     /*
  620.      *    initialize corners of 2 triangles to form rectangle for texture sprite
  621.      *    in the render loop we will only be updating the x, y coords,
  622.      *    and on the third sprite we will set the vertex alpha to 0.1,
  623.      *    to make the entire sprite blend with the background, then reset
  624.      *    the vertex alpha to 1
  625.      *
  626.      *                0-----3
  627.      *              |\    |
  628.      *              | \   |
  629.      *              |  \  |
  630.      *              |   \ |
  631.      *              |    \|
  632.      *                1-----2
  633.      *
  634.      */
  635.     //        x  y  z 1/W a  r  g  b  u/W  v/W  dr dg db sr sg sb
  636.     ST( V[0], 0, 0, 1, 1, 1, 1, 1, 1, 0.0, 1.0, 0, 1, 0, 0, 0, 0.5 );
  637.     ST( V[1], 0, 0, 1, 1, 1, 1, 1, 1, 0.0, 0.0, 0, 1, 0, 0, 0, 0.5 );
  638.     ST( V[2], 0, 0, 1, 1, 1, 1, 1, 1, 1.0, 0.0, 0, 1, 0, 0, 0, 0.5 );
  639.     ST( V[3], 0, 0, 1, 1, 1, 1, 1, 1, 1.0, 1.0, 0, 1, 0, 0, 0, 0.5 );
  640.  
  641.     return( true );
  642. }
  643.  
  644. void MenuBarInit( void )
  645. {
  646.     Handle        mBarHndl;
  647.     
  648.     mBarHndl = GetNewMBar( MBAR_RES_ID );
  649.     SetMenuBar( mBarHndl );
  650.     
  651.     gAppleMenu        = GetMenu( APPLE_MENU_ID );
  652.     gFileMenu        = GetMenu( FILE_MENU_ID );
  653.     gEngineMenu        = GetMenu( ENGINE_MENU_ID );
  654.     
  655.     AppendResMenu( gAppleMenu, 'DRVR' );
  656.     
  657.     DrawMenuBar();
  658. }
  659.  
  660. void EventLoop( void )
  661. {
  662.     EventRecord        event;
  663.     
  664.     while( !gbDone )
  665.     {    
  666.         WaitNextEvent( everyEvent, &event, 60L, NULL );
  667.         
  668.         switch( event.what )
  669.         {                
  670.             case mouseDown:        HandleMouseDown( &event );        break;
  671.             case updateEvt:                                        break;
  672.             case nullEvent:                                        break;
  673.             default:                                            break;
  674.         }
  675.     }
  676. }
  677.  
  678. void HandleMouseDown( EventRecord *pevent )
  679. {
  680.     WindowPtr    pWin;
  681.     
  682.     switch( FindWindow( pevent->where, &pWin ) )
  683.     {            
  684.         case inMenuBar:        HandleMenuChoice( MenuSelect( pevent->where ) );             break;    
  685.         case inSysWindow:    SystemClick( pevent, pWin ); redraw();                        break;    
  686.         case inGoAway:        gbDone = (TrackGoAway(pWin, pevent->where) == true);        break;
  687.         case inContent:        redraw();                                                    break;
  688.         case inDrag:        DragWindow( pWin, pevent->where, &qd.screenBits.bounds );
  689.                             Cleanup();
  690.     
  691.                             if( !SetupRAVE() )
  692.                                 Cleanup();
  693.                                 
  694.                             redraw();
  695.                             break;
  696.         default:                                                                        break;
  697.     }
  698. }
  699.  
  700. void HandleMenuChoice( INT32 i32menuChoice )
  701. {
  702.     if( i32menuChoice == 0 )
  703.         return;
  704.             
  705.     switch( HiWord( i32menuChoice ) )
  706.     {
  707.         case APPLE_MENU_ID:        HandleAppleChoice( LoWord(i32menuChoice) );        break;
  708.         case FILE_MENU_ID:        HandleFileChoice( LoWord(i32menuChoice) );        break;
  709.         case ENGINE_MENU_ID:    HandleEngineChoice( LoWord(i32menuChoice) );    break;
  710.         default:                                                                break;
  711.     } 
  712.  
  713.     HiliteMenu( 0 );     
  714. }
  715.  
  716. void HandleAppleChoice( UINT32 u32TheItem )
  717. {
  718.     Str255    strAccName;        
  719.     
  720.     switch( u32TheItem )
  721.     {
  722.         default:    GetMenuItemText( gAppleMenu, u32TheItem, strAccName );
  723.                     OpenDeskAcc( strAccName );            
  724.                     break;
  725.     }
  726. }
  727.  
  728. void HandleFileChoice( UINT32 u32TheItem )
  729. {
  730.     switch( u32TheItem )
  731.     {
  732.         case QUIT_ITEM:        gbDone = true;        break;
  733.         default:                                break;
  734.     }
  735. }
  736.  
  737. void HandleEngineChoice( UINT32 u32TheItem )
  738. {
  739.     UINT32    vendorID;
  740.     
  741.     for( int i = 1; i <= gNumEngines; i++ )
  742.         CheckItem( gEngineMenu, i, false );
  743.  
  744.     gEngineID    = u32TheItem-1;
  745.     gEngine     = EngineList[gEngineID];
  746.     
  747.     QAEngineGestalt( gEngine, kQAGestalt_VendorID, &vendorID );        
  748.     gbATIcard     = ( vendorID == 1 );
  749.     
  750.     if( QAEngineCheckDevice( gEngine, &gDevice ) )
  751.          printf( "ERROR: EngineCheckDevice failed\n" );
  752.  
  753.     CheckItem( gEngineMenu, u32TheItem, true );
  754.     
  755.     Cleanup();
  756.     
  757.     if( !SetupRAVE() )
  758.         Cleanup();
  759.     
  760.     redraw();
  761. }
  762.  
  763. /*
  764.  * Function:    Cleanup()
  765.  *
  766.  */
  767. void Cleanup( void )
  768. {
  769.     if( gpTex )
  770.     {
  771.         QATextureDelete( gEngine, gpTex );
  772.         gpTex = NULL;
  773.     }
  774.  
  775.     if( gpBit )
  776.     {
  777.         QABitmapDelete( gEngine, gpBit );
  778.         gpBit = NULL;
  779.     }
  780.         
  781.     if( gDrawContext )
  782.     {
  783.         QADrawContextDelete( gDrawContext );
  784.         gDrawContext = NULL;
  785.     }
  786. }
  787.  
  788. void redraw( void )
  789. {
  790.     if( gbATIcard )
  791.     {
  792.         scale     = 1.0;
  793.         pad        = 0.0;
  794.     }
  795.     else
  796.     {
  797.         scale     = 0.5;
  798.         pad        = 175;
  799.  
  800.     }
  801.     
  802.     count     = 0;
  803.     sum        = 0.0;
  804.     
  805.     while( !Button() )
  806.     {
  807.         start = MicrosecondCount();      
  808.  
  809.         /*
  810.          * render loop
  811.          */
  812.         QARenderStart( gDrawContext, NULL, NULL);
  813.  
  814.         /*
  815.          * set current texture
  816.          */
  817.         QASetPtr( gDrawContext, kQATag_Texture, gpTex );
  818.                 
  819.         /*
  820.          * shift first texture 'sprite' + set texture lighting to highlight
  821.          */
  822.         Translate( x1, y1, xinc1, yinc1, gImageTex );
  823.         QASetInt( gDrawContext, kQATag_TextureOp, kQATextureOp_Highlight );        
  824.         QADrawTriTexture( gDrawContext, &V[0], &V[1], &V[2], kQATriFlags_None );
  825.         QADrawTriTexture( gDrawContext, &V[0], &V[2], &V[3], kQATriFlags_None );
  826.         
  827.         /*
  828.          * shift and rotate second texture 'sprite' + set texture lighting to modulate
  829.          */
  830.         Translate( x2, y2, xinc2, yinc2, gImageTex );    
  831.         Rotate( x2, y2, angle, gImageTex );
  832.         QASetInt( gDrawContext, kQATag_TextureOp, kQATextureOp_Modulate );
  833.         QADrawTriTexture( gDrawContext, &V[0], &V[1], &V[2], kQATriFlags_None );
  834.         QADrawTriTexture( gDrawContext, &V[0], &V[2], &V[3], kQATriFlags_None );
  835.         
  836.         /*
  837.          * shift third texture 'sprite' with vertex transparency + turn off texture lighting
  838.          */
  839.         Translate( x3, y3, xinc3, yinc3, gImageTex );
  840.         V[0].a = V[1].a = V[2].a = V[3].a = 0.1;
  841.         QASetInt( gDrawContext, kQATag_TextureOp, kQATextureOp_None );
  842.         QADrawTriTexture( gDrawContext, &V[0], &V[1], &V[2], kQATriFlags_None );
  843.         QADrawTriTexture( gDrawContext, &V[0], &V[2], &V[3], kQATriFlags_None );
  844.         V[0].a = V[1].a = V[2].a = V[3].a = 1.0;
  845.  
  846.         /*
  847.          * shift bitmap 'sprite'
  848.          */        
  849.         Translate( x4, y4, xinc4, yinc4, gImageBit );
  850.         VG.x = x4; VG.y = y4;
  851.         QADrawBitmap( gDrawContext, &VG, gpBit );
  852.  
  853.         QARenderEnd( gDrawContext, NULL );
  854.         
  855.         /*
  856.          * display frame rate
  857.          */
  858.         end     = MicrosecondCount();
  859.         seconds = (float)(MAX((end-start),1))*MILLIONTHS;
  860.         sum        += seconds;
  861.         sprintf( str, "fps = %5.2f, avg = %5.2f", 1.0/seconds, ++count/sum );
  862.         DisplayString( 2, 10, str );
  863.     }
  864. }    
  865.  
  866. /*
  867.  *    Function:    DisplayString()
  868.  *
  869.  */
  870. void DisplayString( int x, int y, char *str )
  871. {
  872.     char buf[256];
  873.     
  874.     if( !winPtr )
  875.         return;
  876.             
  877.     SetPort( winPtr );
  878.     RGBForeColor( &BLACK );
  879.     MoveTo( x, y );
  880.     
  881.     strcpy( buf+1, str );
  882.     buf[0] = strlen( buf+1 );
  883.     DrawString( (const unsigned char *)buf );
  884. }
  885.  
  886. /*
  887.  *    Function:    MicrosecondCount()
  888.  *
  889.  */
  890. UINT32 MicrosecondCount( void )
  891. {    
  892.     UnsignedWide currentCount;
  893.     
  894.     Microseconds(¤tCount);
  895.     
  896.     return( currentCount.lo );
  897. }
  898.  
  899. /*
  900.  *    Function:    LoadImageFromResource()
  901.  *
  902.  */
  903. int LoadImageFromResource(     short resID, UINT8 depth, UINT8 alpha, 
  904.                             TQAImage *map, TQAImagePixelType *pixelType )
  905. {
  906.     PicHandle        hPict;
  907.     Rect            pictRect;
  908.     GDHandle        saveGD;
  909.     GWorldPtr        saveGW;
  910.     PixMapHandle    pixHndl;
  911.     PixMapPtr        pixPtr;
  912.  
  913.     /*
  914.      * determine target pixel type
  915.      */
  916.     switch( depth )
  917.     {
  918.         case 8:     *pixelType = kQAPixel_CL8;                                  break;
  919.         case 16: *pixelType = (alpha) ? kQAPixel_ARGB16 : kQAPixel_RGB16; break;
  920.         case 32: *pixelType = (alpha) ? kQAPixel_ARGB32 : kQAPixel_RGB32; break;
  921.         default: return( false );
  922.     }
  923.  
  924.     /*
  925.      * load PICT resource and get bounding rect
  926.      */    
  927.     if( (hPict = GetPicture( resID )) == NULL )
  928.         return( false );
  929.     
  930.     pictRect = (**hPict).picFrame;
  931.  
  932.     /*
  933.      * setup GWorld to draw pict into
  934.      */     
  935.     GetGWorld( &saveGW, &saveGD );
  936.     
  937.     if( NewGWorld(&newGW, depth, &pictRect, NULL, NULL, NULL) != noErr )
  938.     {
  939.         ReleaseResource( (Handle)hPict );
  940.         return( false );
  941.     }
  942.     
  943.     LockPixels( newGW->portPixMap );
  944.     SetGWorld( newGW, NULL );
  945.     
  946.     DrawPicture(hPict, &pictRect );
  947.  
  948.     /*
  949.      * setup TQAImage struct with GWorld pixmap data
  950.      */    
  951.     pixHndl         = GetGWorldPixMap( newGW );        
  952.     pixPtr            = *pixHndl;
  953.     map->width         = pictRect.right - pictRect.left;
  954.     map->height     = pictRect.bottom - pictRect.top;
  955.     map->rowBytes    = (UINT32)(pixPtr->rowBytes & 0x7fff);
  956.     map->pixmap        = GetPixBaseAddr( pixHndl );
  957.  
  958.     /*
  959.      * Hack to demo sprite with alpha transparency -
  960.      * detect white pixels (in 'Sun' PICT from Scrapbook)
  961.      * and set their alpha bit to 0 for transparency
  962.      */        
  963.     if( alpha )
  964.     {
  965.         UINT8    *u8ptr = (UINT8 *)map->pixmap;
  966.         UINT16    *u16ptr;
  967.         
  968.         for( int y = 0; y < map->height; y++ )
  969.         {
  970.             u16ptr    = (UINT16 *)u8ptr;
  971.             
  972.             for( int x = 0; x < map->width; x++ )
  973.             {
  974.                 if( (u16ptr[x] & 0x7FFF) == 0x7FFF )
  975.                     u16ptr[x] &= 0x8000;
  976.                 else
  977.                     u16ptr[x] |= 0x8000;
  978.             }
  979.             
  980.             u8ptr += map->rowBytes;
  981.         }
  982.     }
  983.     
  984.     /*
  985.      * free PICT resource, delete temp GWorld,
  986.      * and restore old GWorld
  987.      */    
  988.     ReleaseResource( (Handle)hPict );
  989.     SetGWorld( saveGW, saveGD );
  990.     
  991.     return( true );
  992. }
  993.  
  994.